有狀態的物件,把複雜的邏輯判斷分配到不同的狀態物件中,允許狀態物件在其內部狀態發生改變時改變行為。
比如說,人在開心的時候會開懷大笑,在傷心的時候會哭泣,在生氣的時候會想打人...等等,根據不同的狀態,會有不同的行為。而在系統中,通常這個行為會用if-else去做判斷,對應不同的情況去做對應的處理。但如果物件的狀態很多,程式碼會變得很複雜,而且當要新增狀態時,要更改if-else的邏輯,這樣就違背了開閉原則,不利於擴充。
而狀態模式的解決方式就是,控制一個物件狀態的條件過於複雜時,把相關判斷娜及取出,放到一系列的狀態類別中,就可以簡化原本複雜的邏輯。
成員 | 功用 |
---|---|
Context(環境) | 定義Client的接口,維護目前的狀態,並將狀態的操作委託給目前狀態物件來處理。 |
State(狀態) | 定義一個接口,用來封裝Context中特定狀態所對應的行為。 |
ConcreteState(實體狀態) | 實現State所定義的方法。 |
可以試想,今天到銀行要辦一張信用卡,申辦的步驟非常的煩瑣如下:
填寫資料後
1. 業務審核:資料是否完整。
2. 行員審核:查看帳戶及信用卡費是否有按時繳交。
3. 信用卡部審核:調閱聯徵紀錄查詢分數。
以上是簡略的步驟,分成ABC三階段。接著就來實作申請信用卡時的步驟。
首先先將抽象狀態以及實體狀態建立起來,在每個不同的狀態中,會有不同的邏輯實作。
//抽象狀態
abstract class State {
public abstract boolean Handle(Context context, boolean status);
}
//實體狀態A:業務審核
class ConcreteStateA extends State {
public boolean Handle(Context context, boolean status) {
if (status){
System.out.println("資料填寫完整,業務審核通過,準備進入行員審核。");
context.setState(new ConcreteStateB());
} else {
System.out.println("業務審核中。");
}
return false;
}
}
//實體狀態B:行員審核
class ConcreteStateB extends State {
public boolean Handle(Context context, boolean status) {
if (status){
System.out.println("行員審核通過,準備進入信用卡部審核。");
context.setState(new ConcreteStateC());
} else {
System.out.println("行員審核中。");
}
return false;
}
}
//實體狀態C:信用卡部審核
class ConcreteStateC extends State {
public boolean Handle(Context context, boolean status) {
if (status){
System.out.println("信用卡部審核通過,寄送信用卡。");
return true;
} else {
System.out.println("信用卡部審核中。");
return false;
}
}
}
接著建立Context環境類,要在內部定義初始狀態,這個範例的初始狀態是業務審核ConcreteStateA。
//環境類
class Context {
private State state;
// 定義環境類的初始狀態
public Context() {
this.state = new ConcreteStateA();
}
//設定狀態
public void setState(State state) {
this.state = state;
}
//讀取狀態
public State getState() {
return(state);
}
//處理請求
public boolean Handle(boolean status) {
return state.Handle(this, status);
}
}
最後在Client來使用看看
import java.util.*;
public class StatePatternClient{
public static void main(String[] args) {
Context context = new Context(); //建立環境
Scanner scanner = new Scanner(System.in);
boolean end = false;
System.out.println("申請已送出,請等待審核結果。");
while (!end){
System.out.println("請輸入選項(1:審核通過;2:繼續審核;3:結束程式):");
int num = scanner.nextInt();
if (num == 1){
end = context.Handle(true); //處理請求
} else if (num == 2){
end = context.Handle(false); //處理請求
} else if (num == 3){
end = true;
} else {
System.out.println("請輸入正確指令" );
}
}
}
}
有狀態的物件,把複雜的邏輯判斷分配到不同的狀態物件中,允許狀態物件在其內部狀態發生改變時改變行為。
Context:定義Client的接口,維護目前的狀態,並將狀態的操作委託給目前狀態物件來處理。
State:定義一個接口,用來封裝Context中特定狀態所對應的行為。
ConcreteState:實現State所定義的方法。
優點
1. 減少物件之間的依賴性。
2. 利於系統的擴中。
3. 定義新的子類別可以很容易的新增新狀態。
缺點
1. 增加系統的類別及物件的個數。
2. 結構與實作都相對複雜。
1. 物件的行為取決於他的狀態,並必須要執行時根據狀態改變他的行為時。
2. 一個操作具有龐大的分支結構,且這些分支決定物件的狀態時。